package ac.beiwo.baas.admin.service;

import ac.beiwo.baas.admin.entity.Clazz;
import ac.beiwo.baas.admin.entity.ClazzAcl;
import ac.beiwo.baas.admin.entity.ClazzAclMethod;
import ac.beiwo.baas.admin.repository.ClazzRepository;
import ac.beiwo.baas.common.entity.SimpleCode;
import ac.beiwo.baas.common.entity.SimpleError;
import com.alibaba.fastjson.JSON;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by Staryet on 15/6/19.
 */
@Service
public class ClazzService {

    private Log log = LogFactory.getLog(getClass());

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ClazzRepository clazzRepository;
    @Autowired
    private FieldService fieldService;

    public Clazz get(String name) throws SimpleError {
        Clazz clazz = getClazzCache(name);
        if (clazz == null) {
            //未找到缓存
            clazz = clazzRepository.findByName(name);
            if (clazz == null) {
                throw new SimpleError(SimpleCode.CLAZZ_NOT_FOUND);
            }
            setClazzCache(name, clazz);
        }
        return clazz;
    }

    public void insert(Clazz clazz, boolean valid) throws SimpleError {
        String name = clazz.getName();
        if (StringUtils.isEmpty(name)) {
            throw new SimpleError(SimpleCode.CLAZZ_NAME_ERROR);
        }
        if (valid && !isNameValid(name)) {
            throw new SimpleError(SimpleCode.CLAZZ_NAME_ERROR);
        }
        Clazz exist = clazzRepository.findByName(name);
        if (exist == null) {
            clazz.setId(null);
            if (clazz.getAcl() == null) {
                //创建默认acl
                ClazzAcl acl = new ClazzAcl();
                acl.setPublicAccess(ClazzAclMethod.INSERT, true);
                acl.setPublicAccess(ClazzAclMethod.DELETE, true);
                acl.setPublicAccess(ClazzAclMethod.UPDATE, true);
                acl.setPublicAccess(ClazzAclMethod.FIND, true);
                clazz.setAcl(acl);
            }
            clazzRepository.insert(clazz);
            //删除缓存
            deleteClazzCache(name);
        } else {
            throw new SimpleError(SimpleCode.CLAZZ_ALREADY_EXIST);
        }
    }

    public void insert(Clazz clazz) throws SimpleError {
        insert(clazz, true);
    }

    public void delete(String name, boolean valid) throws SimpleError {
        Clazz clazz = get(name);
        if (clazz == null) {
            throw new SimpleError(SimpleCode.CLAZZ_NOT_FOUND);
        }
        if (valid && clazz.isInternal()) {
            throw new SimpleError(SimpleCode.CLAZZ_INTERNAL);
        }
        //同时删除字段
        fieldService.deleteAll(name);
        clazzRepository.delete(clazz);
        log.debug("Class " + name + " 已删除");
        //删除缓存
        deleteClazzCache(name);
    }

    public void delete(String name) throws SimpleError {
        delete(name, true);
    }

    public List<Clazz> list() {
        return clazzRepository.findAll();
    }

    /**
     * 检查类名是否合法 (字母开头，只包含字母数字下划线)
     *
     * @param name
     * @return
     */
    public boolean isNameValid(String name) {
        String regex = "^[a-zA-Z][a-zA-Z0-9_]*$";
        return Pattern.matches(regex, name);
    }

    public void setAcl(String name, ClazzAcl acl) throws SimpleError {
        Clazz clazz = get(name);
        clazz.setAcl(acl);
        clazzRepository.save(clazz);
    }

    private Clazz getClazzCache(String name) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String string = ops.get("_Clazz_" + name);
        return JSON.parseObject(string, Clazz.class);
    }

    private void setClazzCache(String name, Clazz clazz) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.set("_Clazz_" + name, JSON.toJSONString(clazz));
    }

    private void deleteClazzCache(String name) {
        redisTemplate.delete("_Clazz_" + name);
        log.debug("Class " + name + " 缓存已清除");
    }

}
